
#include "com_iwthings_x264_X264Jni.h"
#include "ctcpdownload.h"
#include "ctcpupload.h"
#include "cx264decoder.h"
#include "cx264encoder.h"
#include <android/log.h>
#include <android/bitmap.h>


struct VIDEO_X264_CTX
{
    CX264Decoder *decoder;
    CX264Encoder *encoder;
    CTcpUpload   *upload ;
    CTcpDownload *download;
    bool  bdownload;
};

VIDEO_X264_CTX g_video_x264c;

void cb_x264_encode(unsigned char *data, int len)
{

    if(g_video_x264c.upload!= NULL)
    {
        g_video_x264c.upload->Upload((char *)data, len);
    }
}

void cb_x264_download( char *data, int len)
{
    if(g_video_x264c.decoder!= NULL)
    {
        g_video_x264c.decoder->DecodeFrame((char*)data, len);
    }
}



JNIEXPORT jint JNICALL Java_com_iwthings_x264_X264Jni_OpenX264Encoder
(JNIEnv *env, jobject obj, jint userid, jstring ip,  jint port,
 jint width, jint height, jint bitrate, jint fps, jint gop)
{

    int iret = 0;
    const char* strIP;
    strIP = env->GetStringUTFChars(ip, 0);
    //open encoder
    g_video_x264c.encoder = new CX264Encoder;
    if(g_video_x264c.encoder == NULL)
    {
        return -1;
    }
    iret = g_video_x264c.encoder->OpenEncoder(cb_x264_encode,width,height,
                                              fps, bitrate, gop);
    if(iret < 0)
    {
        return -1;
    }
    //open upload
    g_video_x264c.upload = new CTcpUpload;
    iret = g_video_x264c.upload->OpenUpload(userid,strIP,port);
    if(iret < 0)
    {
        __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "x264 OpenUpload error ip: %s  port:%d" ,strIP,port);
        delete g_video_x264c.upload;
        g_video_x264c.upload = NULL;
        return -1;
    }
    env->ReleaseStringUTFChars(ip, strIP);
    __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "OpenX264Encoder" );

    return 0;
}

JNIEXPORT jint JNICALL Java_com_iwthings_x264_X264Jni_CloseX264Encoder
(JNIEnv *env, jobject obj)
{
    //close encoder
    if(g_video_x264c.encoder != NULL)
    {
        g_video_x264c.encoder->CloseEncoder();
        delete g_video_x264c.encoder;
        g_video_x264c.encoder = NULL;
    }
    //close upload
    if(g_video_x264c.upload != NULL)
    {
        g_video_x264c.upload->CloseUpload();
        delete g_video_x264c.upload;
        g_video_x264c.upload = NULL;
    }
    return 0;
}


JNIEXPORT jint JNICALL Java_com_iwthings_x264_X264Jni_X264Encoder
(JNIEnv *env, jobject obj, jbyteArray in)
{
    if(g_video_x264c.encoder == NULL)
    {
        return -1;
    }
    int ret = 0;
    char *pin = (char*)env->GetByteArrayElements(in, 0);
    ret = g_video_x264c.encoder->EncodeFrame(pin);
    env->ReleaseByteArrayElements( in, (jbyte*)pin,   0);
    return ret;
}

JNIEXPORT jint JNICALL Java_com_iwthings_x264_X264Jni_OpenX264Decode
(JNIEnv *env, jobject obj, jint userid, jstring ip, jint port)
{
    int iret = 0;
    const char* strIP;
    strIP = env->GetStringUTFChars(ip, 0);

    //open download
    g_video_x264c.download = new CTcpDownload;
    g_video_x264c.bdownload = false;

    iret = g_video_x264c.download->OpenDownload(userid,&cb_x264_download,strIP,port);
    if(iret < 0)
    {
        __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "x264 OpenDownload error ip: %s  port:%d" ,strIP,port);
        delete g_video_x264c.download;
        g_video_x264c.download = NULL;
        return -1;
    }

    g_video_x264c.decoder = new CX264Decoder;
    iret = g_video_x264c.decoder->OpenDecode();

    if(iret < 0)
    {
        delete g_video_x264c.decoder;
        g_video_x264c.decoder = NULL;
        return -1;
    }

    __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "OpeX264Decoder" );

    env->ReleaseStringUTFChars(ip, strIP);
    return 0;
}


JNIEXPORT jint JNICALL Java_com_iwthings_x264_X264Jni_CloseX264Decoder
(JNIEnv *env, jobject obj)
{
    if(g_video_x264c.download != NULL)
    {
        g_video_x264c.download->CloseDownload();
        while(g_video_x264c.bdownload)
        {
            //__android_log_print(ANDROID_LOG_INFO, "JNIMsg", "264 download" );
            usleep(100);
        }
        delete g_video_x264c.download;
        g_video_x264c.download = NULL;
    }


    if(g_video_x264c.decoder != NULL)
    {
        g_video_x264c.decoder->CloseDecode();
        delete g_video_x264c.decoder;
        g_video_x264c.decoder = NULL;
    }

    return 0;
}

JNIEXPORT jint JNICALL Java_com_iwthings_x264_X264Jni_x264Decoder
(JNIEnv *env, jobject obj)
{
    if(g_video_x264c.download != NULL)
    {
        g_video_x264c.bdownload = true;
        g_video_x264c.download->Download();
        g_video_x264c.bdownload = false;
    }

    return 0;
}

JNIEXPORT jint JNICALL Java_com_iwthings_x264_X264Jni_GetWidth
(JNIEnv *env, jobject obj)
{
    if(g_video_x264c.decoder != NULL)
    {
        return g_video_x264c.decoder->GetWidth();
    }
    return 0;
}


JNIEXPORT jint JNICALL Java_com_iwthings_x264_X264Jni_GetHeight
(JNIEnv *env, jobject obj)
{
    if(g_video_x264c.decoder != NULL)
    {
        return g_video_x264c.decoder->GetHeight();
    }
    return 0;
}


JNIEXPORT jint JNICALL Java_com_iwthings_x264_X264Jni_Render
(JNIEnv *env, jobject obj, jobject bitmap)
{
    // __android_log_print(ANDROID_LOG_INFO, "JNIMSG", "video render begin");
    AndroidBitmapInfo  info;
    void*     pixels;
    int       ret;

    if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0)
    {
        __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "AndroidBitmap_getInfo error");
        return -1;
    }

    if (info.format != ANDROID_BITMAP_FORMAT_RGB_565)
    {
        __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "ANDROID_BITMAP_FORMAT_RGB_565 error");
        return -1;
    }

    if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0)
    {
        __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "AndroidBitmap_lockPixels error");
    }

    if(g_video_x264c.decoder != NULL)
    {
        g_video_x264c.decoder->Render(pixels, info.width, info.height);
    }

    AndroidBitmap_unlockPixels(env, bitmap);
    return 0;
}
